<?php

/**
 * This is the model class for table "msgg_config".
 *
 * The followings are the available columns in table 'msgg_config':
 * @property integer $id
 * @property string $name
 * @property string $type
 * @property string $status
 * @property integer $try
 * @property integer $level
 * @property string $config
 * @property string $strConfig
 */
class MsggConfig extends CActiveRecord
{
    use util_array;
    //for verify
    const DEFAULT_PARAMS_ADDRESS = 'yunchun.chen@baishancloud.com';
    const DEFAULT_PARAMS_PHONE = '18650451902';
    const DEFAULT_PARAMS_WECHAT = 'cyc';

    const VERIFY_PARAM_PREFIX = 'verify_param';

    const LAST_MODIFY_CACHE_KEY = 'last_modify_cache_key';

    const DEFAULT_LEVEL = '20';
    const DEFAULT_TRY = '3';

    const STATUS_OPEN = 'open';
    const STATUS_CLOSE = 'close';

    public $searchKey = '';

    private static $_options;

    private $_config = false;

    public function tableName()
    {
        return 'msgg_config';
    }

    public function rules()
    {
        return array(
            array('type, status,try,name,level', 'required'),
            array('name', 'length', 'max' => 64),
            array('type', 'length', 'max' => 32),
            array('status', 'length', 'max' => 16),
            array('config, strConfig', 'safe'),
            array('searchKey', 'safe'),
            array('id, name, type, status, config, try,strConfig', 'safe', 'on' => 'search'),
            array('level, try', 'numerical', 'integerOnly' => true, 'min' => 1),
            array('name', 'nameUniqueValidator'),
            array('status', 'statusValidator'),
        );
    }

    public function attributeLabels()
    {
        return array(
            'id' => 'ID',
            'name' => '配置名称',
            'type' => '配置类型',
            'status' => '状态',
            'try' => '重试上限',
            'level' => '优先级',
            'config' => '配置信息',
            'strConfig' => '自定义配置'
        );
    }

    protected function beforeValidate()
    {
        if ($this->isNewRecord && empty($this->status)) {
            $this->status = self::STATUS_CLOSE;
        }
        if ($config = ($this->parseStrConfig($this->strConfig))) {
            $this->config = json_encode($config);
        } else {
            $this->config = null;
        }
        return parent::beforeValidate();
    }

    protected function afterSave()
    {
        self::updateLastModify();
        parent::afterSave();

    }

    protected function afterDelete()
    {
        self::updateLastModify();
        parent::afterDelete();
    }

    public function nameUniqueValidator($attribute)
    {
        if ($attribute == 'name') {
            $name = $this->name;
            $type = $this->type;
            $result = $this->findByAttributes(['name' => $name, 'type' => $type]);
            if (!empty($result->id) && $result->id != $this->id) {
                $this->addError($attribute, "name must be unique in the same type");
            }
        }
    }

    public function statusValidator($attribute)
    {
        if ($attribute != 'status') {
            return;
        }
        if ($this->isOpen() && !$this->hasErrors()) {
            $result = $this->verify();
            if ($result['code'] != 0) {
                $this->addError($attribute, json_encode($result));
            }
        }
    }

    public function verify($params = [])
    {
        $result = array('code' => 0, 'msg' => '');
        try {
            $config = $this->getConfig();
            $defaultParams = array();
            $defaultParams['debug'] = 'bsc';
            switch ($this->type) {
                case MsggItem::TYPE_SMS:
                    $defaultParams['phone'] = null;
                    $defaultParams['param'] = 'Test only';
                    break;
                case MsggItem::TYPE_WECHAT:
                    $defaultParams['to'] = null;
                    $defaultParams['content'] = 'This is a test msg!';
                    break;
                case MsggItem::TYPE_CALL:
                    $defaultParams['phone'] = null;
                    $defaultParams['media'] = MsggItem::DEFAULT_KEY;
                    break;
                case MsggItem::TYPE_MAIL:
                    $defaultParams['address'] = null;
                    $defaultParams['title'] = 'Test Mail';
                    $defaultParams['content'] = 'Test Mail';
                    break;
                default:
                    return $result;
                    break;
            }
            foreach ($defaultParams as $key => $value) {
                if (empty($params[$key])) {
                    $paramKey = implode('_', array(self::VERIFY_PARAM_PREFIX, $key));
                    $params[$key] = empty($config[$paramKey]) ? $value : $config[$paramKey];
                }
            }
            $channelConfig = new ChannelConfig($this);
            $result = MsggItem::build($this->type, $params)->execute(true, [$channelConfig->getChannelConfig()]);
        } catch (Exception $e) {
            $result['code'] = 1;
            $result['msg'] = $e->getMessage();
        }
        return $result;
    }

    public function getConfig()
    {
        if ($this->_config === false) {
            if (!($this->_config = json_decode($this->config, true))) {
                $this->_config = array();
            }
        }
        return $this->_config;
    }

    public function searchByKey()
    {
        $criteria = new CDbCriteria;
        if (!isset($_GET['MsggConfig_sort'])) {
            $criteria->order = 't.status DESC , t.type , t.level';
        }
        if (!empty($this->type)) {
            $criteria->addColumnCondition(array('type' => $this->type));
        }
        if (!empty($this->status)) {
            $criteria->addColumnCondition(array('status' => $this->status));
        }
        if ($this->searchKey !== '') {
            $criteria->addSearchCondition('config', $this->searchKey, true, 'OR');
            $criteria->addSearchCondition('name', $this->searchKey, true, 'OR');
            $criteria->addSearchCondition('type', $this->searchKey, true, 'OR');
            $criteria->addSearchCondition('status', $this->searchKey, true, 'OR');
        }
        return new CActiveDataProvider($this, array(
            'criteria' => $criteria,
        ));
    }

    public function searchByReader(ConfigReader $reader)
    {
        return $reader->searchByKey($this);
    }

    public function copy()
    {
        $model = new self();
        $model->attributes = $this->attributes;
        $model->status = self::STATUS_CLOSE;
        $model->name = implode('_', array($this->name, self::model()->count('type=:type', [':type' => $this->type])));
        $model->level = self::DEFAULT_LEVEL;
        $model->try = self::DEFAULT_TRY;
        return $model;
    }

    private function parseStrConfig($str)
    {
        $config = [];
        $str = rtrim(str_replace("\r\n", "\n", $str), " ;\n");
        if (is_string($str)) {
            $config = [];
            $rows = explode(";\n", $str);
            if (is_array($rows)) {
                foreach ($rows as $row) {
                    $columns = explode('=', $row, 2);
                    $key = trim($columns[0], " ");
                    $value = trim(!is_null($columns[1]) ? $columns[1] : '', " ");
                    if (empty($key)) {
                        continue;
                    }
                    if ($values = explode(',', $value)) {
                        if (sizeof($values) > 1) {
                            $value = $values;
                        }
                    }
                    $config[$key] = $value;
                }
            }
        }
        return $config;
    }

    public function isClose()
    {
        return $this->status == self::STATUS_CLOSE;
    }

    public function isOpen()
    {
        return $this->status == self::STATUS_OPEN;
    }

    public static function model($className = __CLASS__)
    {
        return parent::model($className);
    }

    public static function getLastModify()
    {
        $lastModify = null;
        if (Yii::app()->cache) {
            $lastModify = Yii::app()->cache->get(self::LAST_MODIFY_CACHE_KEY);
        }
        if (empty($lastModify)) {
            $lastModify = self::updateLastModify();
        }
        return $lastModify;
    }

    public static function updateLastModify()
    {
        $time = time();
        if (Yii::app()->cache) {
            Yii::app()->cache->set(self::LAST_MODIFY_CACHE_KEY, $time);
        }
        return $time;
    }

    public static function getOptions($attribute, $options = [])
    {

        if (!isset(self::$_options[$attribute])) {
            $opts = [];
            switch ($attribute) {
                case 'status':
                    $opts[self::STATUS_CLOSE] = 'close';
                    $opts[self::STATUS_OPEN] = 'open';
                    break;
                case 'try':
                    $opts["1"] = 1;
                    $opts["2"] = 2;
                    $opts["3"] = 3;
                    break;
                case 'type':
                    $opts = MsggItem::getOptions('type', [MsggGlobalConfig::CONFIG_TYPE => '全局配置', AppConfig::CONFIG_TYPE => '应用配置']);
                    break;
            }
            self::$_options[$attribute] = $opts;
        }
        if (is_array($options) && !empty($options)) {
            foreach (self::$_options[$attribute] as $k => $v) {
                $options[$k] = $v;
            }
        } else {
            $options = self::$_options[$attribute];
        }
        return $options;

    }

    public static function verifiedAll()
    {
        $result = array('code' => 0, 'data' => []);
        $criteria = new CDbCriteria();
        $criteria->addInCondition('type', array_keys(MsggItem::getOptions('type')));
        $criteria->addColumnCondition(['open' => MsggConfig::STATUS_OPEN]);
        $channelConfigs = MsggConfig::model()->findAll($criteria);
        foreach ($channelConfigs as $channelConfig) {
            $verifiedResult = $channelConfig->verify();
            if ($verifiedResult['code'] != 0) {
                $result['code'] = 1;
                $result['data'][$channelConfig->name] = $verifiedResult['msg'];
            }

        }
        return $result;
    }

    public static function readConfigs(ConfigReader $reader = null)
    {
        if (empty($reader)) {
            return MsggConfig::model()->findAll();
        } else {
            return $reader->read();
        }

    }

}